package com.example.juc.big_talk_concurrent.chapter1.article4;

public class Client {
    static  int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()-> {
            for(int i = 0; i< 5000; i++){
                count++;
            }
        }, "t1");
        Thread t2 = new Thread(()-> {
            for(int i = 0; i< 5000; i++){
                count--;
            }
        }, "t2");
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(count);
    }

    /**
     * 0: getstatic     #11                 // Field count:I
     * 3: iconst_1
     * 4: iadd
     * 5: putstatic     #11                 // Field count:I
     * 8: return
     */
    public void add(){
        count++;
    }
}

//耳熟能详的问题，我们无法保证这段代码执行结果的一定性（正确性），可能是正数、也可能是负数、当然也可能是 0。
//
//那么，我们就把这段代码称为线程不安全的，就是说在单线程环境下正常运行的一段代码，在多线程环境中可能发生各种意外情况，导致无法得到正确的结果。
//
//从线程安全的角度来反向理解线程不安全的概念可能更容易点，这里参考《Java 并发编程实践》上面的一句话：
//
//一段代码在被多个线程访问后，它仍然能够进行正确的行为，那这段代码就是线程安全的。
//
//至于这段代码线程不安全的原因，就是 Java 中对静态变量自增和自减操作并不是原子操作，它俩其实都包含三个离散的操作：
//
//步骤 1：读取当前 i 的值
//步骤 2：将 i 的值加 1（减 1）
//步骤 3：写回新值
//可以看出来这是一个 读 - 改 - 写 的操作。
//
// 在多线程的环境下，由于 CPU 时间片调度的原因，可能 Thread1 正在执行自增操作着呢，CPU 剥夺了它的资源占用，转而分配给了 Thread2，也就是发生了线程上下文切换。这样，就可能导致本该是一个连续的读改写动作（连续执行的三个步骤）被打断了。
//
// 除了自增自减，我们常见的 i = j 这个操作也是非原子性的，它分为两个离散的步骤：
//
//步骤 1：读取 j 的值
//步骤 2：将 j 的值赋给 i
